package com.example.rabbitmqdemo.retry.service;

import cn.hutool.cache.CacheListener;
import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import com.example.rabbitmqdemo.cacheTask.FailCallRecordCacheHandle;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class RetryService {

    @Value("${callRecordFail.pushMail.period:60}")
    private Integer pushMailPeriod;

    @Async
    @Retryable(value = MyException.class, maxAttempts = 1, backoff = @Backoff(value = 1000, multiplier = 2))
    public void testRetry(String key, LocalDateTime now) {
        try {
            log.error("---{} testRetry ", LocalDateTime.now());
            int b = 10 / 0;
        } catch (Exception e) {
            throw new MyException(e.getMessage(), e, new Model(key, now));
        }
    }

    @Recover
    public void recover(Exception e) {
        log.error("--------- {}  ", e.getMessage());
    }

    @Recover
    public void recover(MyException e) {

        FailCallRecordCacheHandle.Factory.create().put(e.model.getKey(), e.model.getNow().toString(), pushMailPeriod);
        log.error("--------- {}  ", e.model);
        log.error(e.getMessage());
    }

    @PostConstruct
    public void setListener() {
        FailCallRecordCacheHandle.Factory.create().setListener((key, values) -> {
            log.error("-- remove key {} ,value {}", key, values);
        });
    }

    private String getKey(String key) {
        LocalDateTime now = LocalDateTime.now();
        StringBuilder result = new StringBuilder(key);
        result.append("_");
        result.append(now.getYear());
        result.append(now.getMonth());
        result.append(now.getDayOfMonth());
        result.append(now.getHour());
        result.append(now.getMinute() + 1);
        return result.toString();
    }

    private class MyException extends RuntimeException {
        Model model;

        public MyException(String msg, Throwable throwable, Model m) {
            super(msg, throwable);
            this.model = m;
        }
    }

    public class Model {
        private String key;
        private LocalDateTime now;

        public Model(String key, LocalDateTime now) {
            this.key = key;
            this.now = now;
        }

        public String getKey() {
            return key;
        }

        public void setKey(String key) {
            this.key = key;
        }

        public LocalDateTime getNow() {
            return now;
        }

        public void setNow(LocalDateTime now) {
            this.now = now;
        }
    }
}
